package top.yongyan0624.controller;


import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.code.kaptcha.Producer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;
import top.yongyan0624.common.dto.PassDto;
import top.yongyan0624.common.exception.CaptchaException;
import top.yongyan0624.common.lang.Const;
import top.yongyan0624.common.lang.Result;
import top.yongyan0624.entity.*;
import top.yongyan0624.utils.EmailUtils;

import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author yongyan
 * @since 2021-08-15
 */
@RestController
@RequestMapping("/sys/user")
public class SysUserController extends BaseController {
    @Autowired
    BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private Producer producer;

    @GetMapping("/email")
    public Result email(String email) {
        String key = UUID.randomUUID().toString();
        String code = producer.createText();

        // 为了 Postman 测试
        // key = "aaaaa";
        // code = "11111";

        //发送邮件
        EmailUtils.sendEmail(email, "【智慧小巷】验证码",
                "<div style='font-size: 20px;font-weight: 700'>【智慧小巷】验证码：" + String.valueOf(code) +
                        "</div><br/><div>您正在进行【智慧小巷】邮箱验证<br/>（若非本人操作，请删除本邮件）<div/>");
        //正确答案存redis里
        redisUtils.hset(Const.EMAIL_KEY, key, code, 600);

        return Result.success(
                MapUtil.builder()
                        .put("token", key)
                        .build());
    }

    @PostMapping("/register")
    public Result register(@Validated @RequestBody SysUser sysUser) {

        if (StringUtils.isBlank(sysUser.getToken()) || StringUtils.isBlank(sysUser.getCode())) {
            //输入为空，抛出异常
            throw new CaptchaException("验证码错误");
        }

        if (!sysUser.getCode().equals(redisUtils.hget(Const.EMAIL_KEY, sysUser.getToken()))) {
            //从redis中取出的code与用户输入的code不相等，抛出异常
            throw new CaptchaException("验证码错误");
        }
        //验证码只能使用一次，所以认证成功要删除
        redisUtils.hdel(Const.EMAIL_KEY, sysUser.getToken());

        // 加密密码
        String password = passwordEncoder.encode(sysUser.getPassword());
        sysUser.setPassword(password);

        // 默认头像
        sysUser.setAvatar(Const.DEFULT_AVATAR);

        // 默认背景
        sysUser.setBgImg(Const.DEFULT_BACKGROUND);

        sysUserService.save(sysUser);

        return Result.success(sysUser);
    }

    @GetMapping("/findPwdEmail")
    public Result findPwdEmail(String username) {
        SysUser user = sysUserService.getByUsername(username);
        if (user == null) {
            return Result.fail("该用户不存在");
        }
        return email(user.getEmail());
    }

    @PostMapping("/findPwd")
    public Result findPwd(@Validated @RequestBody SysUser sysUser) {

        if (StringUtils.isBlank(sysUser.getToken()) || StringUtils.isBlank(sysUser.getCode())) {
            //输入为空，抛出异常
            throw new CaptchaException("验证码错误");
        }

        if (!sysUser.getCode().equals(redisUtils.hget(Const.EMAIL_KEY, sysUser.getToken()))) {
            //从redis中取出的code与用户输入的code不相等，抛出异常
            throw new CaptchaException("验证码错误");
        }
        //验证码只能使用一次，所以认证成功要删除
        redisUtils.hdel(Const.EMAIL_KEY, sysUser.getToken());

        SysUser user = sysUserService.getByUsername(sysUser.getUsername());

        // 加密密码
        String password = passwordEncoder.encode(sysUser.getPassword());
        user.setPassword(password);

        sysUserService.updateById(user);

        return Result.success(user);
    }

    @PostMapping("/modify")
    public Result modify(@Validated @RequestBody SysUser sysUser) {
        sysUserService.updateById(sysUser);
        return Result.success(sysUser);
    }

    @PostMapping("/modifyEmail")
    public Result modifyEmail(@Validated @RequestBody SysUser sysUser) {

        if (StringUtils.isBlank(sysUser.getToken()) || StringUtils.isBlank(sysUser.getCode())) {
            //输入为空，抛出异常
            throw new CaptchaException("验证码错误");
        }

        if (!sysUser.getCode().equals(redisUtils.hget(Const.EMAIL_KEY, sysUser.getToken()))) {
            //从redis中取出的code与用户输入的code不相等，抛出异常
            throw new CaptchaException("验证码错误");
        }
        //验证码只能使用一次，所以认证成功要删除
        redisUtils.hdel(Const.EMAIL_KEY, sysUser.getToken());

        sysUserService.updateById(sysUser);
        return Result.success(sysUser);
    }

    @PostMapping("/modifyAvatar/{id}")
    public Result modifyAvatar(@PathVariable("id") Long id, MultipartFile file) {
        SysUser user;
        try {
            if (file.isEmpty()) {
                return Result.fail("文件为空");
            }

            //文件不为空，处理文件（存储文件并生成随机虚拟文件名）
            String fileName = handleFile("user", id, file);

            //更新user头像
            user = sysUserService.getById(id);
            user.setAvatar(fileName);
            sysUserService.updateById(user);

        } catch (IllegalStateException | IOException e) {
            e.printStackTrace();
            return Result.fail("头像上传失败！");
        }
        return Result.success(user);
    }

    @GetMapping("/info/{id}")
    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result info(@PathVariable("id") Long id) {

        SysUser sysUser = sysUserService.getById(id);
        Assert.notNull(sysUser, "找不到该管理员");

        List<SysRole> roles = sysRoleService.listRolesByUserId(id);
        sysUser.setRoles(roles);
        return Result.success(sysUser);
    }

    @GetMapping("/list")
    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result list(String username) {

        Page<SysUser> pageData = sysUserService.page(getPage(), new QueryWrapper<SysUser>()
                .like(StrUtil.isNotBlank(username), "username", username));

        pageData.getRecords().forEach(u -> {
            u.setRoles(sysRoleService.listRolesByUserId(u.getId()));
        });

        return Result.success(pageData);
    }

    @PostMapping("/save")
    @PreAuthorize("hasAuthority('sys:user:save')")
    public Result save(@Validated @RequestBody SysUser sysUser) {
        // 默认密码
        String password = passwordEncoder.encode(Const.DEFULT_PASSWORD);
        sysUser.setPassword(password);

        // 默认头像
        sysUser.setAvatar(Const.DEFULT_AVATAR);

        // 默认背景
        sysUser.setBgImg(Const.DEFULT_BACKGROUND);

        sysUserService.save(sysUser);
        return Result.success(sysUser);
    }

    @PostMapping("/update")
    @PreAuthorize("hasAuthority('sys:user:update')")
    public Result update(@Validated @RequestBody SysUser sysUser) {
        sysUserService.updateById(sysUser);
        return Result.success(sysUser);
    }

    @Transactional
    @PostMapping("/delete")
    @PreAuthorize("hasAuthority('sys:user:delete')")
    public Result delete(@RequestBody Long[] ids) {

        sysUserService.removeByIds(Arrays.asList(ids));
        //删除所有与这些用户有关联的记录
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("user_id", ids));
        voteService.remove(new QueryWrapper<Vote>().in("user_id", ids));
        voteUserService.remove(new QueryWrapper<VoteUser>().in("user_id", ids));
        storeCartService.remove(new QueryWrapper<StoreCart>().in("user_id", ids));
        storeCartGroupService.remove(new QueryWrapper<StoreCartGroup>().in("user_id", ids));
        shopService.remove(new QueryWrapper<Shop>().in("user_id", ids));
        propertyRepairService.remove(new QueryWrapper<PropertyRepair>().in("user_id", ids));
        propertyPayService.remove(new QueryWrapper<PropertyPay>().in("user_id", ids));
        propertyComplaintService.remove(new QueryWrapper<PropertyComplaint>().in("user_id", ids));
        itemLostService.remove(new QueryWrapper<ItemLost>().in("user_id", ids));
        itemFindService.remove(new QueryWrapper<ItemFind>().in("user_id", ids));
        itemBorrowUserService.remove(new QueryWrapper<ItemBorrowUser>().in("user_id", ids));
        itemBorrowService.remove(new QueryWrapper<ItemBorrow>().in("user_id", ids));
        goodsGroupService.remove(new QueryWrapper<GoodsGroup>().in("user_id", ids));
        goodsService.remove(new QueryWrapper<Goods>().in("user_id", ids));
        dynamicUserService.remove(new QueryWrapper<DynamicUser>().in("user_id", ids));
        dynamicCommentService.remove(new QueryWrapper<DynamicComment>().in("user_id", ids));
        dynamicService.remove(new QueryWrapper<Dynamic>().in("user_id", ids));
        alipayGroupService.remove(new QueryWrapper<AlipayGroup>().in("user_id", ids));
        alipayService.remove(new QueryWrapper<Alipay>().in("user_id", ids));
        noticeService.remove(new QueryWrapper<Notice>().in("user_id", ids));

        return Result.success("");
    }

    @Transactional
    @PostMapping("/role/{userId}")
    @PreAuthorize("hasAuthority('sys:user:role')")
    public Result rolePerm(@PathVariable("userId") Long userId, @RequestBody Long[] roleIds) {

        List<SysUserRole> userRoles = new ArrayList<>();

        Arrays.stream(roleIds).forEach(r -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleId(r);
            sysUserRole.setUserId(userId);

            userRoles.add(sysUserRole);
        });

        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().eq("user_id", userId));
        sysUserRoleService.saveBatch(userRoles);

        // 删除缓存
        SysUser sysUser = sysUserService.getById(userId);
        sysUserService.clearUserAuthorityInfo(sysUser.getId());

        return Result.success("");
    }

    @PostMapping("/repass")
    @PreAuthorize("hasAuthority('sys:user:repass')")
    public Result repass(@RequestBody Long userId) {

        SysUser sysUser = sysUserService.getById(userId);

        sysUser.setPassword(passwordEncoder.encode(Const.DEFULT_PASSWORD));

        sysUserService.updateById(sysUser);
        return Result.success("");
    }

    @PostMapping("/updatePass")
    public Result updatePass(@Validated @RequestBody PassDto passDto, Principal principal) {

        SysUser sysUser = sysUserService.getByUsername(principal.getName());

        boolean matches = passwordEncoder.matches(passDto.getCurrentPass(), sysUser.getPassword());
        if (!matches) {
            return Result.fail("旧密码不正确");
        }

        sysUser.setPassword(passwordEncoder.encode(passDto.getPassword()));

        sysUserService.updateById(sysUser);
        return Result.success("");
    }
}
